﻿using System.Linq;
using System.IO;

using NUnit.Framework;
using Ninject;

using System.Net.DnsToolkit.Bastard.PacketGenerator;
using System.Net.DnsToolkit.Configuration;
using System.Net.DnsToolkit.Packet;
using System.Net.DnsToolkit.Serializer;
using System.Net.DnsToolkit.Util;
using System.Net.DnsToolkit.TestUnit.Helper;

namespace System.Net.DnsToolkit.TestUnit.Bastard.PacketGenerator {
    [TestFixture]
    public class DomainPointerMultiLoopTest {

        [Test]
        public void TestGetBytes() {

            var generator = new DomainPointerMultiLoop();
            var bs = generator.GetBytes();
            var result = BitStringHelper.ByteArrayToString(bs);

            Assert.AreEqual("000000000005000000000000027130C01500010001027131C01E00010001027132C02700010001027133C03000010001027134C00C00010001", result, "result");

        }

        [Test]
        public void TestReadMessage() {

            var generator = new DomainPointerMultiLoop();
            var bs = generator.GetBytes();

            var message = DnsReader.Read(new MemoryStream(bs));
            // DarkDns toolkit is immune to DomainPointerMultiLoop attack
            Assert.AreEqual(5, message.Questions.Count, "count");
            Assert.AreEqual(5, message.Header.QuestionCount, "header count");
            Assert.AreEqual("q0.q1.q2.q3.q4.q0.", message.Questions[0].QName.Name, "question0");
            Assert.AreEqual("q1.q2.q3.q4.q0.q1.", message.Questions[1].QName.Name, "question1");
            Assert.AreEqual("q2.q3.q4.q0.q1.q2.", message.Questions[2].QName.Name, "question2");
            Assert.AreEqual("q3.q4.q0.q1.q2.q3.", message.Questions[3].QName.Name, "question3");
            Assert.AreEqual("q4.q0.q1.q2.q3.q4.", message.Questions[4].QName.Name, "question4");

        }

        [Test]
        public void TestReadMessageCustom() {

            var generator = new DomainPointerMultiLoop("dark", "dns", "bastard", "lousy", "rocks", "your", "ass");
            var bs = generator.GetBytes();

            var message = DnsReader.Read(new MemoryStream(bs));
            // DarkDns toolkit is immune to DomainPointerMultiLoop attack
            Assert.AreEqual(7, message.Questions.Count, "count");
            Assert.AreEqual(7, message.Header.QuestionCount, "header count");
            Assert.AreEqual("dark.dns.bastard.lousy.rocks.your.ass.dark.", message.Questions[0].QName.Name, "question0");
            Assert.AreEqual("dns.bastard.lousy.rocks.your.ass.dark.dns.", message.Questions[1].QName.Name, "question1");
            Assert.AreEqual("bastard.lousy.rocks.your.ass.dark.dns.bastard.", message.Questions[2].QName.Name, "question2");
            Assert.AreEqual("lousy.rocks.your.ass.dark.dns.bastard.lousy.", message.Questions[3].QName.Name, "question3");
            Assert.AreEqual("rocks.your.ass.dark.dns.bastard.lousy.rocks.", message.Questions[4].QName.Name, "question4");
            Assert.AreEqual("your.ass.dark.dns.bastard.lousy.rocks.your.", message.Questions[5].QName.Name, "question5");
            Assert.AreEqual("ass.dark.dns.bastard.lousy.rocks.your.ass.", message.Questions[6].QName.Name, "question6");

        }

        public void FindBestMessage() {

            for (int i = 0; i < 500; i++) {
                for (int j = 0; j < 100; j++) {

                    var ss = "q".Repeat(i).Multiply(j);

                    var generator = new DomainPointerMultiLoop(ss);
                    var bs = generator.GetBytes();

                    if (bs.Length > 512) {
                        continue;
                    }
                    var message = DnsReader.Read(new MemoryStream(bs));

                    Console.WriteLine("{0} {1} {2} {3}", i, j, bs.Length, message.Questions.Count);

                }
            }
        }

        
    }
}
